/// Computed[T] represents an effect that subscribes to a continuous data source.
/// It is a subtype of Source[T]. Different from general Source, a Computed
/// holds a current value and always produces its current value synchronously
/// as its first value.
type Computed [out T]
    protected
    Source[T];


export function Computed:[T]
    &(Source[T], { beginning: List[T] }) => Computed[T]
    native '__ComputedFromSource';


export method Computed.sample: Sync[T]
    native '__ComputedSample';


export function map:[A,B]
    &(Computed[A], &(A) => B) => Computed[B]
    native '__ComputedMap';

export function map:[A,B,X]
    &((Computed[A],Computed[B]), &(A,B) => X) => Computed[X]
    native '__ComputedLiftAx';

export function map:[A,B,C,X]
    &((Computed[A],Computed[B],Computed[C]), &(A,B,C) => X) => Computed[X]
    native '__ComputedLiftAx';

export function map:[A,B,C,D,X]
    &((Computed[A],Computed[B],Computed[C],Computed[D]), &(A,B,C,D) => X) => Computed[X]
    native '__ComputedLiftAx';

export function switch-map:[A,B]
    &(Computed[A], &(A) => Computed[B]) => Computed[B]
    native '__ComputedSwitchMap';

export function memo-map:[A,B]
    &(Computed[A], &(A) => B) => Sync[Computed[B]]
    native '__ComputedMemoMap';

export function list-map:[A,B]
    { <>: Op<>[A] }
    &(Computed[List[A]], &(A) => Computed[B]) => Computed[List[B]]
    native '__ComputedListMap';


export function with-value-from:[A,B]
    &(Computed[A], Mutable[B]) => Computed[(A,B)]
    native '__ComputedWithValueFrom';

export function combine:[A,B]
    &(Computed[A],Computed[B]) => Computed[(A,B)]
    native '__ComputedCombine';

export function combine:[A,B,C]
    &(Computed[A],Computed[B],Computed[C]) => Computed[(A,B,C)]
    native '__ComputedCombine';

export function combine:[A,B,C,D]
    &(Computed[A],Computed[B],Computed[C],Computed[D]) => Computed[(A,B,C,D)]
    native '__ComputedCombine';

export function combine:[T]
    &(List[Computed[T]]) => Computed[List[T]]
    native '__ComputedCombineList';


export function not:
    &(Computed[Bool]) => Computed[Bool]
    &(p) => p.{map(not)};

export function and:
    &(Computed[Bool], Computed[Bool]) => Computed[Bool]
    &(p,q) => ((p,q) map &(p,q) => (p and q));

export function or:
    &(Computed[Bool], Computed[Bool]) => Computed[Bool]
    &(p,q) => ((p,q) map &(p,q) => (p or q));


